// EG4DCHit.cc -- implementation of the class for hits of DCs
// Created: Jan. 22, 2019, by Asia SUN, asia.rabbit@163.com
// Last Modified: Jan. 31, 2019 by Asia SUN

#include "EG4DCHit.h"
#include "G4VVisManager.hh"
#include "G4VisAttributes.hh"
#include "G4Circle.hh"
#include "G4AttDefStore.hh"
#include "G4AttDef.hh"
#include "G4AttValue.hh"
#include "G4UIcommand.hh"
#include "G4LogicalVolume.hh"
#include "G4UnitsTable.hh" // G4BestUnit
#include "G4SystemOfUnits.hh"
#include "G4ios.hh"

using std::cout;
using std::endl;

G4ThreadLocal G4Allocator<EG4DCHit> *EG4DCHit::dchAlloc = nullptr;

EG4DCHit::EG4DCHit(int DCID) : G4VHit(){
  Initialize();
} // end ctor

EG4DCHit::~EG4DCHit(){}

void EG4DCHit::Initialize(){
  fParentId = fTrackId = fType = fDCId = fWireLayerId = -1; fName = "";
  fTrkLen = fCharge = fMass = fTime = fEk = fEdep = fV = -999.;
  fPos.set(0., 0., 0.); fLocalPos.set(0., 0., 0.);
  fP.set(0., 0., 0.); fRot.set(0., 0., 0.);
  fLV = nullptr;
} // end memeber function initialize

EG4DCHit::EG4DCHit(const EG4DCHit &right) : G4VHit(){
  if(&right != this) *this = right;
} // end copy ctor

EG4DCHit &EG4DCHit::operator=(const EG4DCHit &p){
  fParentId = p.fParentId; fTrackId = p.fTrackId; fType = p.fType;
  fDCId = p.fDCId; fWireLayerId = p.fWireLayerId; fName = p.fName;
  fCharge = p.fCharge; fMass = p.fMass; fTime = p.fTime;
  fEk = p.fEk; fEdep = p.fEdep; fV = p.fV; fHitPos = p.fHitPos;
  fPos = p.fPos; fLocalPos = p.fLocalPos; fP = p.fP; fRot = p.fRot; fTrkLen = p.fTrkLen;
  fLV = p.fLV;

  return *this;
} // end assignment ctor

bool EG4DCHit::operator==(const EG4DCHit &p) const{
  return fTime == p.fTime && fHitPos == p.fHitPos && fP == p.fP;
} // end member function opeartor==

void EG4DCHit::Draw(){
  G4VVisManager *vm = G4VVisManager::GetConcreteInstance();
  if(!vm) return;

  G4Circle circle(fHitPos);
  circle.SetScreenSize(15);
  circle.SetFillStyle(G4Circle::filled);
  if(0 == fType) circle.SetVisAttributes(new G4VisAttributes(G4Colour(1., 0., 0.)));
  if(1 == fType) circle.SetVisAttributes(new G4VisAttributes(G4Colour(0., 1., 0.)));
  vm->Draw(circle);
} // end member function Draw

const map<G4String, G4AttDef> *EG4DCHit::GetAttDefs() const{
  bool isNew; // check if "EG4DCHit" is a new element in the map
  map<G4String, G4AttDef> *store = G4AttDefStore::GetInstance("EG4DCHit", isNew);
  
  if(isNew){
    // the following two constructor styles are equivalent
    (*store)["Ek"]
      //             name,         description,    category,  extra,      valueType
      = G4AttDef("Ek", "Kinetic Energy", "Physics", "G4BestUnit", "double");
    (*store)["Edep"] = G4AttDef("Edep", "Energy deposition", "Physics", "G4BestUnit", "double");
    (*store)["trkLen"] = G4AttDef("trkLen", "track length", "Physics", "G4BestUnit", "double");
    (*store)["HitType"] = G4AttDef("HitType", "Hit Type", "Physics", "", "G4String");
		(*store)["DCId"] = G4AttDef("DCId", "Drift Chamber Id", "Detector", "", "G4int");
    (*store)["WireLayerID"] = G4AttDef("WireLayerID", "Sense Wire Layer ID",
			"Detector", "", "G4int");
    (*store)["Time"] = G4AttDef("Time", "Time", "Physics", "", "double");
    (*store)["V"] = G4AttDef("V", "Velocity", "Physics", "", "double");
    (*store)["Pos"] = G4AttDef("Pos", "Position", "Physics", "", "G4ThreeVector");
    (*store)["P"] = G4AttDef("P", "Momentum", "Physics", "G4BestUnit", "G4ThreeVector");
    (*store)["LV"] = G4AttDef("LV", "Logical Volume", "Physics", "", "G4String");
  } // end if

  return store;
} // end member function GetAttDefs

vector<G4AttValue> *EG4DCHit::CreateAttValues() const{
  vector<G4AttValue> *values = new vector<G4AttValue>;
  values->push_back(G4AttValue("HitType", "EG4Hit", ""));
  values->push_back(G4AttValue("DCId", G4UIcommand::ConvertToString(fDCId), ""));
  values->push_back(G4AttValue("WireLayerId", G4UIcommand::ConvertToString(fWireLayerId), ""));
  values->push_back(G4AttValue("Time", G4BestUnit(fTime, "Time"), ""));
  // (G4String &name, G4String &value, G4String &showLabel)
  values->push_back(G4AttValue("V", G4UIcommand::ConvertToString(fV), " mm/ns"));
  values->push_back(G4AttValue("Ek", G4BestUnit(fEk, "Energy"), ""));
  values->push_back(G4AttValue("Edep", G4BestUnit(fEdep, "Energy"), ""));
  values->push_back(G4AttValue("trkLen", G4BestUnit(fTrkLen, "Length"), ""));
  values->push_back(G4AttValue("Pos", G4BestUnit(fPos, "Length"), ""));
  values->push_back(G4AttValue("P", G4BestUnit(fP, "Momentum"), ""));
  if(fLV) values->push_back(G4AttValue("LV", fLV->GetName(), ""));
  else values->push_back(G4AttValue("LV", "", ""));

  return values;
} // end member function CreateAttValues

void EG4DCHit::Print(){
  cout << endl << "---------- DC " << fLV->GetName() << " HIT --------- " << endl;
  cout << "Parent ID: " << fParentId << " Track ID: " << fTrackId << endl;
  cout << "  " << fName << ", mass: " << fMass << ", charge: " << fCharge << endl;
  cout << "DC[" << fDCId << "], WireLayer[" << fWireLayerId << "]" << endl;
  cout << "Time: " << fTime/ns << " ns" << endl;
  cout << "V: " << fV << " mm/ns, Ek: " << G4BestUnit(fEk, "Energy");
  cout << " , Ek/u: " << G4BestUnit(fEk/fMass, "Energy");
  cout << " , Edep: " << G4BestUnit(fEdep, "Energy") << endl;
  cout << "Pos: " << fPos << ", P: " << fP << endl;
  cout << "Local Pos: " << fLocalPos;
  if(-999. != fTrkLen) cout << "trkLen: " << G4BestUnit(fTrkLen, "Length") << endl;
} // end member function Print

void *EG4DCHit::operator new(size_t){
  if(!dchAlloc) dchAlloc = new G4Allocator<EG4DCHit>;
  return dchAlloc->MallocSingle();
} // end overloaded new

void EG4DCHit::operator delete(void *hit){
  dchAlloc->FreeSingle((EG4DCHit*)hit);
} // end overloaded delete

void EG4DCHit::Assign(hit_t &t) const{
  t.pid = fParentId; t.tid = fTrackId;
  t.id[0] = fDCId; t.id[1] = fWireLayerId;
  t.a = fMass; t.z = fCharge; t.t = fTime;
  t.v = fV; t.ek = fEk; t.de = fEdep; t.trkLen = fTrkLen;
  EG4Data::copy(t.pos, fHitPos); EG4Data::copy(t.p, fP);
} // end member function Assign
